#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <fcntl.h>
#include <unistd.h>
#include <arpa/inet.h>
#include "common.h"
#include "ofprint_common.h"
#include "usb_device.h"
#include "upgrade.h"
#include "app_fp256_360.h"


/********************函数预定义********************/
int32 fp_upload_fprint_img(FP_DEVICE_PARAM_STRUCT *this);
int32 fp_onekey_restart_identify(FP_DEVICE_PARAM_STRUCT *this, uint16 *identify_result_id, int32 wait_ms);
/**************************************************/


int32 fp_module_init(FP_DEVICE_PARAM_STRUCT *this)
{
    if(NULL == this)
    {
        WD_ERR("the param is ERROR!\n");
        return DRV_ERR;
    }

    //memset((uint8 *)&prot_packet_usb, 0, sizeof(PROT_PACKET));
    memset((uint8 *)this, 0, sizeof(FP_DEVICE_PARAM_STRUCT));

    usb_dev_module_init(&(this->usb_dev));

    return DRV_OK;
}

/*取得校验和*/
static uint16 get_check_sum(uint8 *buf, uint16 len)
{
    uint32 i = 0;
    uint16 checksum = 0;

    if (NULL == buf)
    {
        WD_ERR("the point buf is null, error!!!\r\n");
        return 0;
    }

    for (i = 0; i < len; i++)
    {
        checksum += buf[i];
    }

    return (checksum);
}


static int32 fp_recv_param_init(RECV_DATA_STRUCT *recv_param, int32 recv_len, uint16 wait_ms, uint16 cycle_times, uint16 cycle_ms)
{
    if(NULL == recv_param)
    {
        WD_ERR("the point recv_param is null, error!!!\r\n");
        return DRV_ERR;
    }

    memset((uint8 *)recv_param, 0x00, sizeof(RECV_DATA_STRUCT));

    recv_param->recv_len = recv_len;
    recv_param->wait_ms = wait_ms;
    recv_param->cycle_times = cycle_times;
    recv_param->cycle_ms = cycle_ms;

    return DRV_OK;
}



static int32 fp_resp_init(PROT_PACKET *p, uint8 cmd_code)
{
    if(NULL == p)
    {
        WD_ERR("the param is ERROR!\n");
        return DRV_ERR;
    }

    p->current_cmd_code = cmd_code;
    p->current_resp_cmd = 0;
    p->current_resp_type = 0xff;

    return DRV_OK;
}

static uint8 fp_resp_type_get(PROT_PACKET *p)
{
    if(NULL == p)
    {
        WD_ERR("the param is ERROR!\n");
        return DRV_ERR;
    }

    return p->current_resp_type;
}


static int32 fp_parse_prot_response(FP_DEVICE_PARAM_STRUCT *this, uint8 *buf, int32 len)
{
    uint8 current_cmd_code = this->prot_packet_usb.current_cmd_code;
    uint8 confirm_code = 0;
    PROT_PACKET *p = &(this->prot_packet_usb);
    USB_DEV_STRUCT *usb_dev;
    //FP_DEVICE_PARAM_STRUCT *dev_param = this;

    if((NULL == this) || (NULL == buf) || (0 >= len))
    {
        WD_ERR("the param is error!!!\r\n");
        return DRV_ERR;
    }

    confirm_code = buf[0];
    p->current_resp_type = confirm_code;
    usb_dev = &(this->usb_dev);

    switch(current_cmd_code)
    {
        case PROT_CMD_GETIMAGE:     //验证用获取图像
            DBG("%s:%d:%s: received PROT_CMD_GETIMAGE response.\r\n", __FILE__, __LINE__, __func__);
            p->current_resp_cmd = PROT_CMD_GETIMAGE;
            break;
        case PROT_CMD_GENCHAR:break;        //根据原始图像生成指纹特征存于文件缓冲区
        case PROT_CMD_MATCH:break;          //精确比对特征文件缓冲区中的特征文件
        case PROT_CMD_SEARCH:break;         //以特征文件缓冲区中的特征文件搜索整个或部分指纹库
        case PROT_CMD_REGMODEL:break;       //将特征文件合并生成模板存于特征文件缓冲区
        case PROT_CMD_STORECHAR:break;      //将特征缓冲区中的文件储存到flash指纹库中
        case PROT_CMD_LOADCHAR:break;       //从 flash 指纹库中读取一个模板到特征缓冲区
        case PROT_CMD_UPCHAR:break;         //将特征缓冲区中的文件上传给上位机
        case PROT_CMD_DOWNCHAR:break;       //从上位机下载一个特征文件到特征缓冲区
        case PROT_CMD_UPIMAGE:      //上传原始图像
            DBG("%s:%d:%s: received PROT_CMD_UPIMAGE response.\r\n", __FILE__, __LINE__, __func__);
            p->current_resp_cmd = PROT_CMD_UPIMAGE;
            break;
        case PROT_CMD_DOWNIMAGE:break;      //下载原始图像
        case PROT_CMD_DELCHAR:      //删除 flash 指纹库中的一个特征文件
            DBG("%s:%d:%s: received PROT_CMD_DELCHAR response.\r\n", __FILE__, __LINE__, __func__);
            p->current_resp_cmd = PROT_CMD_DELCHAR;
            this->delete_template_result = confirm_code;
            break;
        case PROT_CMD_EMPTY:            //清空 flash 指纹库
            DBG("%s:%d:%s: received PROT_CMD_EMPTY response.\r\n", __FILE__, __LINE__, __func__);
            p->current_resp_cmd = PROT_CMD_EMPTY;
            this->empty_template_result = confirm_code;
            break;
        case PROT_CMD_READSYSPARA:  //读系统基本参数
            DBG("%s:%d:%s: received PROT_CMD_READSYSPARA response.\r\n", __FILE__, __LINE__, __func__);
            p->current_resp_cmd = PROT_CMD_READSYSPARA;
            this->sys_param.sensor_type = ((buf[1]<<8) & 0xff00) | (buf[2] & 0x00ff);
            this->sys_param.fp_database_size = ((buf[3]<<8) & 0xff00) | (buf[4] & 0x00ff);
            this->sys_param.security_level = ((buf[5]<<8) & 0xff00) | (buf[6] & 0x00ff);
            this->sys_param.device_addr = ((buf[7]<<24) & 0xff000000) \
                                                | ((buf[8]<<16) & 0x00ff0000) \
                                                | ((buf[9]<< 8) & 0x0000ff00) \
                                                | (buf[10] & 0x000000ff);
            DBG("%s:%d:%s: sensor_type = 0x%04x, fp_database_size = 0x%04x, security_level = 0x%04x, device_addr = 0x%08x.\r\n", \
                __FILE__, __LINE__, __func__, this->sys_param.sensor_type, this->sys_param.fp_database_size, \
                this->sys_param.security_level, this->sys_param.device_addr);
            break;
        case PROT_CMD_SETPWD:break;         //设置设备握手口令
        case PROT_CMD_VFYPWD:break;         //验证设备握手口令

        case PROT_CMD_SETCHIPADDR:  //设置芯片地址
            DBG("%s:%d:%s: received PROT_CMD_SETCHIPADDR response.\r\n", __FILE__, __LINE__, __func__);
            p->current_resp_cmd = PROT_CMD_SETCHIPADDR;
            break;
        case PROT_CMD_READINFOPAGE: //读取 FLASH Information Page 内容
            DBG("%s:%d:%s: received PROT_CMD_READINFOPAGE response.\r\n", __FILE__, __LINE__, __func__);
            p->current_resp_cmd = PROT_CMD_READINFOPAGE;
            break;
        case PROT_CMD_HIGHSPEEDSEARCH:break;    //高速搜索FLASH
        case PROT_CMD_VALIDTEMPLATENUM: //读有效模板个数
            DBG("%s:%d:%s: received PROT_CMD_VALIDTEMPLATENUM response.\r\n", __FILE__, __LINE__, __func__);
            if(PROT_RESP_OK == confirm_code)
            {
                this->valid_template_num = ((buf[1]<<8) & 0xff00) | (buf[2] & 0x00ff);
            }
            p->current_resp_cmd = PROT_CMD_VALIDTEMPLATENUM;
            break;
        case PROT_CMD_READINDEXTABLE:   //读索引表
            DBG("%s:%d:%s: received PROT_CMD_READINDEXTABLE response.\r\n", __FILE__, __LINE__, __func__);
            p->current_resp_cmd = PROT_CMD_READINDEXTABLE;
            if(4 > this->index_table_page)
            {
                memcpy(this->index_table_info[this->index_table_page], buf + 1, 32);
                {
                    for(int16 i = 0; i < 32; i++)
                    {
                        DBG("%02x ", this->index_table_info[this->index_table_page][i]);
                    }
                    DBG("\r\n");
                }
            }
            break;
        case PROT_CMD_GETENROLLIMAGE:break; //注册用获取图像
        case PROT_CMD_CANCEL:       //取消指令
            DBG("%s:%d:%s: received PROT_CMD_CANCEL response.\r\n", __FILE__, __LINE__, __func__);
            p->current_resp_cmd = PROT_CMD_CANCEL;
            this->cancel_result = confirm_code;
            break;
        case PROT_CMD_AUTOENROLL:   //自动注册模块指令
            D_DBG("received PROT_CMD_AUTOENROLL response.\r\n");
            p->current_resp_cmd = PROT_CMD_AUTOENROLL;
            switch(buf[1])
            {
                case 0x00:
                    this->auto_enroll_param.validity_check_result = confirm_code;
                    D_DBG("validity_check_result = 0x%02x.\r\n", \
                        this->auto_enroll_param.validity_check_result);
                    break;
                case 0x01:
                    this->auto_enroll_param.capture_result[buf[2]] = confirm_code;
                    this->auto_enroll_param.current_enroll_time = buf[2];
                    D_DBG("capture_result[%d] = 0x%02x.\r\n", \
                        buf[2], this->auto_enroll_param.capture_result[buf[2]]);
                    break;
                case 0x02:
                    this->auto_enroll_param.create_feature_result[buf[2]] = confirm_code;
                    this->auto_enroll_param.current_enroll_time = buf[2];
                    D_DBG("create_feature_result[%d] = 0x%02x.\r\n", \
                        buf[2], this->auto_enroll_param.create_feature_result[buf[2]]);
                    break;
                case 0x03:
                    this->auto_enroll_param.enroll_result[buf[2]] = confirm_code;
                    this->auto_enroll_param.current_enroll_time = buf[2];
                    this->auto_enroll_param.current_enroll_flag = 1;
                    D_DBG("enroll_result[%d] = 0x%02x.\r\n", \
                        buf[2], this->auto_enroll_param.enroll_result[buf[2]]);
                    break;
                case 0x04:
                    this->auto_enroll_param.merge_template_result = confirm_code;
                    D_DBG("merge_template_result = 0x%02x.\r\n", \
                        this->auto_enroll_param.merge_template_result);
                    //sleep(1);
                    break;
                case 0x05:
                    this->auto_enroll_param.enroll_conflict_result = confirm_code;
                    WD_DBG("enroll_conflict_result = 0x%02x.\r\n", \
                        this->auto_enroll_param.enroll_conflict_result);
                    break;
                case 0x06:
                    this->auto_enroll_param.store_template_result = confirm_code;
                    this->auto_enroll_param.enroll_finish_flag = 1;
                    WD_DBG("store_template_result = 0x%02x.\r\n", \
                        this->auto_enroll_param.store_template_result);
                    break;
                default:
                    WD_ERR("param buf[1] = 0x%02x, error!!!\r\n", buf[1]);
                    break;
            }
            break;
        case PROT_CMD_AUTOIDENTIFY: //自动验证指纹指令
            D_DBG("received PROT_CMD_AUTOIDENTIFY response.\r\n");
            p->current_resp_cmd = PROT_CMD_AUTOIDENTIFY;
            switch(buf[1])
            {
                case 0x00:
                    this->auto_identify_param.validity_check_result = confirm_code;
                    D_DBG("validity_check_result = 0x%02x.\r\n", \
                        this->auto_identify_param.validity_check_result);
                    break;
                case 0x01:
                    this->auto_identify_param.validity_check_result = PROT_RESP_OK;
                    this->auto_identify_param.capture_result = confirm_code;
                    D_DBG("capture_result = 0x%02x.\r\n", \
                        this->auto_identify_param.capture_result);
                    break;
                case 0x05:
                    this->auto_identify_param.validity_check_result = PROT_RESP_OK;
                    this->auto_identify_param.search_result = confirm_code;
                    this->auto_identify_param.search_num = 1;
                    this->auto_identify_param.search_id[0] = ((buf[2] << 8) & 0xff00) | (buf[3] & 0xff);
                    this->auto_identify_param.score = ((buf[4] << 8) & 0xff00) | (buf[5] & 0xff);
                    this->auto_identify_param.identify_finish_flag = 1;
                    WD_DBG("search_result = 0x%02x, search_id[0] = 0x%04x.\n", \
                        this->auto_identify_param.search_result, this->auto_identify_param.search_id[0]);
                    break;
                case 0xf5:
                    this->auto_identify_param.search_result = confirm_code;
                    this->auto_identify_param.search_num = buf[2];
                    for(int n = 0; n < this->auto_identify_param.search_num; n++)
                    {
                        this->auto_identify_param.search_id[n] = buf[3 + n];
                    }
                    this->auto_identify_param.identify_finish_flag = 1;
                    WD_DBG("search_result = 0x%02x, search_num = %d.\r\n", \
                        this->auto_identify_param.search_result, this->auto_identify_param.search_num);
                    break;
                default:
                    WD_ERR("param buf[1] = 0x%02x, error!!!\r\n", buf[1]);
                    break;
            }
            break;
        case PROT_CMD_SLEEP:            //休眠指令
            D_DBG("received PROT_CMD_SLEEP response.\r\n");
            p->current_resp_cmd = PROT_CMD_SLEEP;
            this->sleep_result = confirm_code;
            break;
        case PROT_CMD_GETCHIPSN:        //获取芯片唯一序列号
            D_DBG("received PROT_CMD_GETCHIPSN response.\r\n");
            p->current_resp_cmd = PROT_CMD_GETCHIPSN;
            if(0x13 == p->prot_size)
            {
                this->chip_serial_num_len = 16;
                memcpy(this->chip_serial_num, buf + 1, 16);
            }
            else if(0x23 == p->prot_size)
            {
                this->chip_serial_num_len = 32;
                memcpy(this->chip_serial_num, buf + 1, 32);
            }
            else
            {
                p->current_resp_type = 0xff;
            }
            break;
        case PROT_CMD_HANDSHAKE:        //握手指令
            WD_DBG("received PROT_CMD_HANDSHAKE response.\r\n");
            p->current_resp_cmd = PROT_CMD_HANDSHAKE;
            this->handshake_state = 1;
            break;
        case PROT_CMD_CHECKSENSOR:break;    //校验传感器
        case PROT_CMD_IIC_LED_CONTROL:break;//IIC接口灯光控制
        case PROT_CMD_PS_PC_STATE:  //设置pc低功耗状态应答
            WD_DBG("received PROT_CMD_PS_PC_STATE response.\r\n");
            p->current_resp_cmd = PROT_CMD_PS_PC_STATE;
            break;
        case PROT_CMD_TEST_TYPE:    //生产测试命令
            D_DBG("received PROT_CMD_TEST_TYPE response.\n");
            p->current_resp_cmd = PROT_CMD_TEST_TYPE;
            switch(p->current_sub_cmd_code)
            {
                case PROT_SUBCMD_READ_FW:
                    //if((26 == len) || (25 == len))
                    if((strlen(THM36_FW_VERSION_HEAD) == (len-1-FW_VERSION_NUM_LEN_MAX))\
                        || (strlen(ACM32_FW_VERSION_HEAD) == (len-1-FW_VERSION_NUM_LEN_MAX))\
                        || (strlen(CCM4201S_FW_VERSION_HEAD) == (len-1-FW_VERSION_NUM_LEN_MAX)))
                    {
                        char *start = NULL;
                        char str_fmt[FW_VERSION_LEN_MAX] = {0};
                        int fw_version_num = 0;

                        memcpy(this->firmware_version, &buf[1], len-1);
                        this->firmware_version[len] = '\0';
                        D_DBG("len-1 =  %d\n", len-1);
                        WD_LOG("firmware_version is %s\n", this->firmware_version);

                        //thm36 MCU
                        start = strstr(this->firmware_version, THM36_FW_VERSION_HEAD);
                        if(start != NULL)
                        {
                            memset(str_fmt, 0x00, FW_VERSION_LEN_MAX);
                            strcpy(str_fmt, THM36_FW_VERSION_HEAD);
                            strcat(str_fmt, "%d");

                            sscanf(start, str_fmt, &fw_version_num);
                            D_DBG("fw_version_num = %d\n", fw_version_num);
                            if((fw_version_num <= 0)||(fw_version_num > 999999))
                            {
                                WD_ERR("固件版本信息错误!\n");
                                break;
                            }
                            this->firmware_version_num = fw_version_num;
                            WD_LOG("firmware_version num is %d\n", this->firmware_version_num);
                            usb_dev_set_mcu_type(usb_dev, DEVICE_THM36);
                            break;
                        }

                        start = strstr(this->firmware_version, ACM32_FW_VERSION_HEAD);
                        if(start != NULL)
                        {
                            memset(str_fmt, 0x00, FW_VERSION_LEN_MAX);
                            strcpy(str_fmt, ACM32_FW_VERSION_HEAD);
                            strcat(str_fmt, "%d");

                            sscanf(start, str_fmt, &fw_version_num);
                            D_DBG("fw_version_num = %d\n", fw_version_num);
                            if((fw_version_num <= 0)||(fw_version_num > 999999))
                            {
                                WD_ERR("固件版本信息错误!\n");
                                break;
                            }
                            this->firmware_version_num = fw_version_num;
                            WD_LOG("firmware_version num is %d\n", this->firmware_version_num);
                            usb_dev_set_mcu_type(usb_dev, DEVICE_ACM32);
                            break;
                        }

                        start = strstr(this->firmware_version, CCM4201S_FW_VERSION_HEAD);
                        if(start != NULL)
                        {
                            memset(str_fmt, 0x00, FW_VERSION_LEN_MAX);
                            strcpy(str_fmt, CCM4201S_FW_VERSION_HEAD);
                            strcat(str_fmt, "%d");

                            sscanf(start, str_fmt, &fw_version_num);
                            D_DBG("fw_version_num = %d\n", fw_version_num);
                            if((fw_version_num <= 0)||(fw_version_num > 999999))
                            {
                                WD_ERR("固件版本信息错误!\n");
                                break;
                            }
                            this->firmware_version_num = fw_version_num;
                            WD_LOG("firmware_version num is %d\n", this->firmware_version_num);
                            usb_dev_set_mcu_type(usb_dev, DEVICE_CCM4201S);
                            break;
                        }
                    }
                    else
                    {
                        this->onekey_powerup.continue_read_fw_version_flag = 1;
                        WD_LOG("not received firmware_version!!!\n");
                        if((6 == len)&&(0x05 == buf[1]))
                        {
                            set_onekey_powerup_flag(this, 1);
                            gettimeofday(&(this->onekey_powerup.tv_current_time), NULL);//若读取到1键开机结果，15秒后未解锁则清空一键开机状态

                            if(0x00 == buf[0])
                            {
                                this->onekey_powerup.search_num = 1;
                                this->onekey_powerup.search_id[0] = ((buf[2] << 8) & 0xff00) | (buf[3] & 0xff);
                                this->onekey_powerup.search_id[1] = 0xffff;
                            }
                            else
                            {
                                WD_DBG("identify failed!\n");
                                this->onekey_powerup.search_num = 0;
                                this->onekey_powerup.search_id[0] = 0xffff;
                            }
                            WD_DBG("search_num = %d, search_id[0] = 0x%04x.\n", \
                                this->onekey_powerup.search_num, this->onekey_powerup.search_id[0]);
                        }
                        else if((6 <= len)&&(0xf5 == buf[1]))
                        {
                            set_onekey_powerup_flag(this, 1);
                            gettimeofday(&(this->onekey_powerup.tv_current_time), NULL);//若读取到1键开机结果，10秒后未解锁则清空一键开机状态
                            if(0x00 == buf[0])
                            {
                                this->onekey_powerup.search_num = buf[2];
                                for(int n = 0; n < this->onekey_powerup.search_num; n++)
                                {
                                    this->onekey_powerup.search_id[n] = buf[3 + n];
                                }
                                this->onekey_powerup.search_id[this->onekey_powerup.search_num] = 0xffff;
                            }
                            else
                            {
                                WD_DBG("identify failed!\n");
                                this->onekey_powerup.search_num = 0;
                                this->onekey_powerup.search_id[0] = 0xffff;
                            }

                            WD_DBG("search_num = %d, search_id[0] = %d.\n", \
                                this->onekey_powerup.search_num, this->onekey_powerup.search_id[0]);
                        }
                    }
                    break;
                default:
                    break;
            }
            break;          //生产测试命令

        /*********************用于BF91360ML*********************/
        case PORT_CMD_SET_BRIGHTNESS:break;     //设置采集器亮度, add by hcq, 20221229
        case PORT_CMD_GET_BRIGHTNESS:           //获取采集器当前亮度
#if 0
            if(PROT_RESP_OK == confirm_code)
            {
                uint16 brightness = ((buf[1] << 8) & 0xff00) | (buf[2] & 0xff);
                p->current_resp_type = PROT_RESP_OK;

                DBG("%s:%d:%s: brightness = 0x%04x\r\n", __FILE__, __LINE__, __func__, brightness);
            }
#endif
            break;
        case PORT_CMD_SET_CONTRAST:break;       //设置采集器当前对比度
        case PORT_CMD_GET_CONTRAST:break;       //获取采集器当前对比度
        case PORT_CMD_GET_MAXSIZEOFIMAGE:break; //获取采集器图片尺寸最大值
        case PORT_CMD_SET_SIZEOFIMAGE:break;    //设置采集器当前图片坐标X，坐标Y，宽度，高度
        case PORT_CMD_GET_SIZEOFIMAGE:break;    //获取采集器当前图片坐标X，坐标Y，宽度，高度
        case PORT_CMD_READYCAPIMAGE:break;      //准备采集一帧图像
        case PORT_CMD_STARTCAPIMAGE:            //采集一帧图像
            if(CONFIRM_CODE_SUCCESS == confirm_code)
            {
                D_DBG("start capture.\r\n");
                p->current_resp_type = PROT_RESP_OK;
                p->current_resp_cmd = PORT_CMD_STARTCAPIMAGE;
            }
            else
            {
                D_DBG("capture failed!!!\r\n");
                p->current_resp_type = confirm_code;
                p->current_resp_cmd = PORT_CMD_STARTCAPIMAGE;
            }
            break;
        case PORT_CMD_ENDCAPIMAGE:break;        //结束采集一帧图像
        /*******************************************************/

        case PROT_CMD_RTBOOT: //返回boot状态，便于下次重烧固件
            WD_DBG("received PROT_CMD_RTBOOT response.\n");
            p->current_resp_cmd = PROT_CMD_RTBOOT;
            break;
        default:
            WD_ERR("not find the current_cmd_code 0x%02x, error!!!\r\n", current_cmd_code);
            return DRV_ERR;
    }

    return DRV_OK;
}

static int32 fp_parse_prot_data_end(FP_DEVICE_PARAM_STRUCT *this, uint8 *buf, int32 len)
{
    uint8 current_cmd_code = 0; // = this->prot_packet_usb.current_cmd_code;
    //FP_DEVICE_PARAM_STRUCT *dev_param = &fp_device_param;
    int32 ret = DRV_OK;

    if((NULL == this) || (NULL == buf) || (0 >= len))
    {
        WD_ERR("the param is error!!!\r\n");
        return DRV_ERR;
    }
    current_cmd_code = this->prot_packet_usb.current_cmd_code;

    switch(current_cmd_code)
    {
        case PROT_CMD_READINFOPAGE:
            if(FLASH_INFO_PAGE_SIZE != len)
            {
                WD_ERR("len = %d, error!!!\r\n", len);
            }
            WD_DBG("acquire flash_info_page data:\r\n");
            {
                int n = len;
                //(len > 64)?(n = 64):(n = len);
                for(int i = 0; i < n; i++)
                {
                    W_DBG("%02x ", buf[i]);
                    if(0 == ((i+1)%32))
                        DBG("\r\n");
                }
                W_DBG("\r\n");
            }

            if(FLASH_INFO_PAGE_SIZE >= len)
            {
                memcpy(this->flash_info_page, buf, len);
            }
            break;
        case PORT_CMD_ACQUIRE_IMAGEDATA:
            if(IMG_SIZE != len)
            {
                WD_ERR("len = %d, error!!!\r\n", len);
            }
            DBG("%s:%d:%s: acquire image data:\r\n", __FILE__, __LINE__, __func__);
            {
                int n;
                (len > 64)?(n = 64):(n = len);
                for(int i = 0; i < n; i++)
                {
                    DBG("%02x ", buf[i]);
                    if(0 == ((i+1)%32))
                        DBG("\r\n");
                }
                DBG("\r\n");
            }
            memcpy(this->img_data, buf, len);
            break;
        default:
            WD_ERR("not find the current_cmd_code 0x%02x, error!!!\r\n", current_cmd_code);
            ret = DRV_ERR;
            break;
    }

    return ret;
}



static int32 fp_parse_prot_head(FP_DEVICE_PARAM_STRUCT *this, uint8 *buf, int32 len)
{
    PROT_PACKET *p = NULL;
    int32 ret = DRV_OK;

    if((NULL == this) || (NULL == buf) || (sizeof(PROT_PACKET) != len))
    {
        WD_ERR("the param is error!!!\r\n");
        return DRV_ERR;
    }

    p = (PROT_PACKET *)buf;

    switch(p->prot_type)
    {
        case PROT_TYPE_CMD: break;
        case PROT_TYPE_DATA: break;
        case PROT_TYPE_RESPOND:
            fp_parse_prot_response(this, p->prot_data, p->prot_data_cnt);
            break;
        case PROT_TYPE_END:
            fp_parse_prot_data_end(this, p->prot_data, p->prot_data_cnt);
            break;
        default:
            WD_ERR("p->prot_type = 0x%02x is error!!!\r\n", p->prot_type);
            ret = DRV_ERR;
            break;
    }

    return ret;
}

/*对USB的命令数据进行处理*/
static int32 fp_deal_usb_data(FP_DEVICE_PARAM_STRUCT *this, uint8 value)
{
    uint8 getchar = 0;
    uint16 sum[4] = {0};
    uint16 checksum = 0;
    int32 ret = DRV_ERR;
    PROT_PACKET *p = NULL;

    if(NULL == this)
    {
        WD_ERR("the param is ERROR!\n");
        return DRV_ERR;
    }
    p = &(this->prot_packet_usb);

    getchar = value;

    switch (p->prot_state)
    {
        case PACKET_IDLE:
            if (getchar == 0xEF)
            {
                p->prot_state = PACKET_HEAD;

                this->usb_recv_cnt = 0;
                this->usb_recv_data[this->usb_recv_cnt++]=getchar;
            }
            break;
        case PACKET_HEAD:
            if (getchar == 0x01)
            {
                p->prot_head = 0xEF01;
                p->prot_state = PACKET_ADDRESS1;

                this->usb_recv_data[this->usb_recv_cnt++]=getchar;
            }
            else
            {
                p->prot_state = PACKET_IDLE;    //包头错误，转初始状态
            }
            break;
        case PACKET_ADDRESS1:
            p->prot_addr  = 0;
            p->prot_addr |= getchar;
            p->prot_addr <<=8;
            p->prot_state = PACKET_ADDRESS2;

            this->usb_recv_data[this->usb_recv_cnt++]=getchar;
            break;
        case PACKET_ADDRESS2:
            p->prot_addr |= getchar;
            p->prot_addr <<=8;
            p->prot_state = PACKET_ADDRESS3;

            this->usb_recv_data[this->usb_recv_cnt++]=getchar;
            break;
        case PACKET_ADDRESS3:
            p->prot_addr |= getchar;
            p->prot_addr <<=8;
            p->prot_state = PACKET_ADDRESS4;

            this->usb_recv_data[this->usb_recv_cnt++]=getchar;
            break;
        case PACKET_ADDRESS4:
            p->prot_addr |= getchar;
            p->prot_state = PACKET_TYPE;
            this->usb_recv_data[this->usb_recv_cnt++]=getchar;
            break;
        case PACKET_TYPE:
            p->prot_type = getchar;
            p->prot_state = PACKET_SIZE1;

            this->usb_recv_data[this->usb_recv_cnt++]=getchar;
            break;
        case PACKET_SIZE1:
            p->prot_size  = 0;
            p->prot_size |= getchar;
            p->prot_size <<=8;
            p->prot_state = PACKET_SIZE2;

            this->usb_recv_data[this->usb_recv_cnt++]=getchar;
            break;
        case PACKET_SIZE2:  //包长度 = 数据内容长度 + 校验位长度
            p->prot_size |= getchar;
            p->prot_data_cnt = 0;
            if (p->prot_size > 2)               //有数据
            {
                p->prot_state = PACKET_DATA;
            }
            else if (p->prot_size == 2) //无数据，直接到校验位
            {
                p->prot_state = PACKET_CHECKSUM1;
            }
            else
            {
                p->prot_state = PACKET_IDLE;
            }

            this->usb_recv_data[this->usb_recv_cnt++] = getchar;
            break;
        case PACKET_DATA:
            p->prot_data[p->prot_data_cnt] = getchar;
            p->prot_data_cnt++;
            if((PORT_CMD_ACQUIRE_IMAGEDATA == p->current_cmd_code) && (0xffff == p->prot_size))
            {
                if(IMG_SIZE <= p->prot_data_cnt)
                {
                    p->prot_state = PACKET_CHECKSUM1;
                }
            }
            else
            {
                if((p->prot_size-2) <= p->prot_data_cnt)
                {
                    p->prot_state = PACKET_CHECKSUM1;
                }
            }

            this->usb_recv_data[this->usb_recv_cnt++]=getchar;
            break;
        case PACKET_CHECKSUM1:
            p->prot_checksum  =0;
            p->prot_checksum |=getchar;
            p->prot_checksum <<=8;
            p->prot_state = PACKET_CHECKSUM2;

            this->usb_recv_data[this->usb_recv_cnt++]=getchar;
            break;
        case PACKET_CHECKSUM2:
            p->prot_checksum |=getchar;
            this->usb_recv_data[this->usb_recv_cnt++]=getchar;
            sum[0] = p->prot_type;
            sum[1] = (p->prot_size & 0xFF00)>>8;
            sum[2] = (p->prot_size & 0xFF);
            sum[3] = get_check_sum(p->prot_data, p->prot_data_cnt);

            checksum = (sum[0]+sum[1]+sum[2]+sum[3])&0xFFFF;

            if((checksum == p->prot_checksum) \
                || ((PORT_CMD_ACQUIRE_IMAGEDATA == p->current_cmd_code) && (CAP_PARAM_VALID_FLAG == p->prot_checksum)))
            {
                p->prot_respond = PROT_RESP_OK;

                if (this->usb_recv_cnt > 0)
                {
                    if (1)//add by hcq, 20221226
                    {
                        int i = 0;
                        int n;
                        WD_DBG("Recv data from device: %d\n", this->usb_recv_cnt);
                        (this->usb_recv_cnt > 64)?(n = 64):(n = this->usb_recv_cnt);
                        for (i = 0; i < n; i++)
                        {
                            W_DBG("%02x ", this->usb_recv_data[i]);
                            if(0 == (i + 1) % 32)
                                W_DBG("\n");
                        }
                        W_DBG("\n");
                    }
                    fp_parse_prot_head(this, (uint8 *)p, sizeof(PROT_PACKET));
                    this->usb_recv_cnt=0;
                }
                ret = DRV_OK;
            }
            else
            {
                WD_ERR("p->prot_checksum = 0x%04x, checksum = 0x%04x, not equal!!!\r\n", p->prot_checksum, checksum);
            }
            p->prot_state = PACKET_IDLE;
            break;
        default:
            break;
    }

    return ret;
}


static int32 fp_parse_prot(FP_DEVICE_PARAM_STRUCT *this, uint8 *buf, int32 len)
{
    int32 i = 0;
    int32 ret = DRV_ERR;

    if((NULL == this) || (NULL == buf) || (0 >= len))
    {
        WD_ERR("the param is error!!!\r\n");
        return DRV_ERR;
    }


    for(i = 0; i < len; i++)
    {
        if(DRV_OK == fp_deal_usb_data(this, buf[i]))
        {
            ret = DRV_OK;
            //break;
        }
    }

    return ret;
}


static int32 fp_fill_msg_head(MSG_HEAD_STRUCT *head, uint8 pkg_flag, uint16 cmd_len)
{
    if(NULL == head)
    {
        WD_ERR("the param is error!!!\r\n");
        return DRV_ERR;
    }

    head->pkg_head = htons(0xEF01);
    head->chip_addr = htonl(0xFFFFFFFF);
    head->pkg_flag = pkg_flag;
    head->pkg_len = htons(cmd_len);

    return DRV_OK;
}

static int32 fp_fill_msg_checksum(uint8 *buf, int32 len)
{
    uint16 checksum = 0;

    if((NULL == buf) || (0 >= len))
    {
        WD_ERR("the param is error!!!\r\n");
        return DRV_ERR;
    }

    checksum = get_check_sum(buf, len);
    buf[len] = (checksum >> 8) & 0xff;//校验和
    buf[len + 1] = checksum & 0xff;//校验和

    return DRV_OK;
}

int32 fp_read_and_parse_prot(FP_DEVICE_PARAM_STRUCT *this, int32 len)
{
    MSG_STRUCT msg;
    int32 read_len = len;

    if((NULL == this) || (0 >= len))
    {
        WD_ERR("the param is ERROR!\r\n");
        return DRV_ERR;
    }

    memset((int8 *)&msg, 0, sizeof(MSG_STRUCT));

    if(DRV_OK != usb_read_data(&(this->usb_dev), (uint8 *)&msg, read_len, &read_len))
    {
        WD_ERR("usb_read_data failed!!!\r\n");
        return DRV_ERR;
    }

    if(DRV_OK != fp_parse_prot(this, (uint8 *)&msg, read_len))
    {
        //WD_ERR("fp_parse_prot failed!!!\n");
        return DRV_ERR;
    }

    return DRV_OK;
}

//发送命令并读取应答
//cmd_code: 命令码, recv_len: 待接收数据长度, wait_ms发送命令后的等待应答时间, cycle_ms: 未读取数据时循环时间, cycle_times未读取到数据时循环次数
static int32 fp_send_cmd(FP_DEVICE_PARAM_STRUCT *this, uint8 cmd_code, uint8 *buf, int32 len, RECV_DATA_STRUCT recv_param)
{
    MSG_STRUCT msg;
    int32 index = 0;
    int32 wr_len = 0;//write or read len
    PROT_PACKET *p = NULL;
    int ret = DRV_OK;
    USB_DEV_STRUCT *usb_dev;

    if(NULL == this)
    {
        WD_ERR("the param is ERROR!\n");
        return DRV_ERR;
    }
    p = &(this->prot_packet_usb);
    usb_dev = &(this->usb_dev);

    memset((int8 *)&msg, 0, sizeof(MSG_STRUCT));

    msg.data[index++] = cmd_code;//指令码

    if((NULL != buf) && (0 < len))
    {
        memcpy((uint8 *)(&(msg.data[index])), buf, len);
        index += len;
    }

    fp_fill_msg_head(&msg.head, PROT_TYPE_CMD, index + CHIP_CHECKSUM_SIZE);
    fp_fill_msg_checksum((uint8 *)&msg.head.pkg_flag, \
            sizeof(msg.head.pkg_flag) + sizeof(msg.head.pkg_len) + index);
    index += CHIP_CHECKSUM_SIZE;

    if(DRV_OK != usb_send_data(usb_dev, (uint8 *)&msg, sizeof(MSG_HEAD_STRUCT) + index, &wr_len))
    {
        WD_ERR("usb_send_data failed!!!\r\n");
        return DRV_ERR;
    }

    if(0 < recv_param.wait_ms)
        usleep(recv_param.wait_ms * 1000);

    ret = DRV_ERR;
    for(int i = 0; i < recv_param.cycle_times; i++)
    {
        fp_resp_init(p, cmd_code);

        if(DRV_OK == fp_read_and_parse_prot(this, recv_param.recv_len))
        {
            ret = DRV_OK;
            break;
        }

        if(recv_param.cycle_ms)
        {
            usleep(recv_param.cycle_ms * 1000);
        }
    }

    if(DRV_OK == ret)
    {
        if(p->current_cmd_code != p->current_resp_cmd)
        {
            WD_ERR("current_cmd_code = 0x%02x, current_resp_cmd = 0x%02x, ERROR!!!\r\n", \
                p->current_cmd_code, p->current_resp_cmd);
            ret = DRV_ERR;
        }
    }

    return ret;
}

struct timeval *get_onekey_powerup_tv_time(FP_DEVICE_PARAM_STRUCT *this)            //一键开机读取到的时间
{
    if(NULL == this)
    {
        WD_ERR("the param is ERROR!\n");
        return NULL;
    }

    return &(this->onekey_powerup.tv_current_time);
}

uint8 get_onekey_powerup_flag(FP_DEVICE_PARAM_STRUCT *this) //获取一键开机标志
{
    if(NULL == this)
    {
        WD_ERR("the param is ERROR!\n");
        return DRV_ERR;
    }

    return this->onekey_powerup.onekey_powerup_flag;
}

int32 set_onekey_powerup_flag(FP_DEVICE_PARAM_STRUCT *this, uint8 flag) //设置一键开机标志
{
    if(NULL == this)
    {
        WD_ERR("the param is ERROR!\n");
        return DRV_ERR;
    }

    this->onekey_powerup.onekey_powerup_flag = flag;
    return DRV_OK;
}

uint16 *get_onekey_powerup_search_id(FP_DEVICE_PARAM_STRUCT *this)
{
    if(NULL == this)
    {
        WD_ERR("the param is ERROR!\n");
        return NULL;
    }

    return this->onekey_powerup.search_id;
}

int32 init_onekey_powerup_search_id(FP_DEVICE_PARAM_STRUCT *this)
{
    if(NULL == this)
    {
        WD_ERR("the param is ERROR!\n");
        return DRV_ERR;
    }

    for(int i = 0; i < ENROLL_NUM_MAX; i++)
    {
        this->onekey_powerup.search_id[i] = 0xffff;
    }

    return DRV_OK;
}

int32 get_onekey_powerup_search_num(FP_DEVICE_PARAM_STRUCT *this)
{
    if(NULL == this)
    {
        WD_ERR("the param is ERROR!\n");
        return DRV_ERR;
    }

    return this->onekey_powerup.search_num;
}

uint8 get_onekey_restart_flag(FP_DEVICE_PARAM_STRUCT *this) //获取一键开机标志
{
    if(NULL == this)
    {
        WD_ERR("the param is ERROR!\n");
        return 0xff;
    }

    return this->onekey_powerup.onekey_restart_flag;
}

int32 set_onekey_restart_flag(FP_DEVICE_PARAM_STRUCT *this, uint8 flag) //设置一键开机标志
{
    if(NULL == this)
    {
        WD_ERR("the param is ERROR!\n");
        return DRV_ERR;
    }

    this->onekey_powerup.onekey_restart_flag = flag;
    return DRV_OK;
}

int32 get_restart_tv_begin_change_ms(FP_DEVICE_PARAM_STRUCT *this)
{
    struct timeval tv_end;
    struct timeval tv_begin = this->onekey_powerup.tv_restart_begin;
    int verify_time_ms = 0;

    if(NULL == this)
    {
        WD_ERR("the param is ERROR!\n");
        return DRV_ERR;
    }

    gettimeofday(&tv_end, NULL);

    if(tv_end.tv_usec > tv_begin.tv_usec)
    {
        verify_time_ms = (tv_end.tv_sec - tv_begin.tv_sec)*1000 +\
            (tv_end.tv_usec - tv_begin.tv_usec)/1000;
    }
    else
    {
        verify_time_ms = (tv_end.tv_sec - tv_begin.tv_sec - 1)*1000 +\
            (tv_end.tv_usec + 1000*1000 - tv_begin.tv_usec)/1000;
    }

    return verify_time_ms;
}


//获取固件版本
int32 fp_get_firmware_version(FP_DEVICE_PARAM_STRUCT *this)
{
    RECV_DATA_STRUCT recv_param;
    uint8 buf[10] = {0};

    DBG("fp_get_firmware_version==========================>enter\n");
    WD_DBG("send PROT_CMD_TEST_TYPE PROT_SUBCMD_READ_FW command.\r\n");

    if(NULL == this)
    {
        WD_ERR("the param is ERROR!\n");
        DBG("fp_get_firmware_version==========================>error exit\n");
        return DRV_ERR;
    }

    fp_recv_param_init(&recv_param, 64, 20, 10, 20);//循环时间由10ms改为20ms, add by hcq, 20230608 08:15

    buf[0] = PROT_SUBCMD_READ_FW;
    this->prot_packet_usb.current_sub_cmd_code = PROT_SUBCMD_READ_FW;

    if(DRV_OK != fp_send_cmd(this, PROT_CMD_TEST_TYPE, buf, 1, recv_param))
    {
        WD_ERR("fp_send_cmd failed!!!\r\n");
        for(int count = 0; count < 5; count++)
        {
            usleep(20 * 1000);
            if(1 != this->onekey_powerup.continue_read_fw_version_flag)
            {
                break;
            }

            if(DRV_OK != fp_read_and_parse_prot(this, recv_param.recv_len))
            {
                break;
            }
        }
        this->onekey_powerup.continue_read_fw_version_flag = 0;

        DBG("fp_get_firmware_version==========================>error exit\n");
        return DRV_ERR;
    }

    for(int count = 0; count < 5; count++)
    {
        usleep(20 * 1000);
        if(1 != this->onekey_powerup.continue_read_fw_version_flag)
        {
            break;
        }

        if(DRV_OK != fp_read_and_parse_prot(this, recv_param.recv_len))
        {
            break;
        }
    }
    this->onekey_powerup.continue_read_fw_version_flag = 0;

    switch(fp_resp_type_get(&(this->prot_packet_usb)))
    {
        case PROT_RESP_OK:
            WD_DBG("received PROT_RESP_OK.\n");
            break;
        default:
            WD_ERR("not received PROT_RESP_OK!!!\r\n");
            DBG("fp_get_firmware_version==========================>error exit\n");
            return DRV_ERR;
    }
    DBG("fp_get_firmware_version==========================>exit\n");

    return DRV_OK;
}

//获取固件版本
char *fp_return_firmware_version(FP_DEVICE_PARAM_STRUCT *this)
{
    if(NULL == this)
    {
        WD_ERR("the param is ERROR!\n");
        return NULL;
    }

    return this->firmware_version;
}

//获取固件版本
uint32 fp_return_firmware_version_num(FP_DEVICE_PARAM_STRUCT *this)
{
    if(NULL == this)
    {
        WD_ERR("the param is ERROR!\n");
        return DRV_ERR;
    }

    return this->firmware_version_num;
}


//上传图像
int32 fp_upload_fprint_img(FP_DEVICE_PARAM_STRUCT *this)
{
    RECV_DATA_STRUCT recv_param;

    WD_DBG("send PROT_CMD_UPIMAGE command.\n");
    if(NULL == this)
    {
        WD_ERR("the param is ERROR!\n");
        return DRV_ERR;
    }

    fp_recv_param_init(&recv_param, 64, 20, 5, 20);//循环时间由10ms改为20ms, add by hcq, 20230608 08:15

    if(DRV_OK == fp_send_cmd(this, PROT_CMD_UPIMAGE, NULL, 0, recv_param))
    {
        switch(fp_resp_type_get(&(this->prot_packet_usb)))
        {
            case PROT_RESP_OK:
                D_DBG("received PROT_RESP_OK.\n");
                this->prot_packet_usb.current_cmd_code = PORT_CMD_ACQUIRE_IMAGEDATA;

                if(DRV_ERR == fp_read_and_parse_prot(this, IMG_SIZE + 20))
                {
                    WD_ERR("fp_read_and_parse_prot failed!!!\r\n");
                    return DRV_ERR;
                }
                break;
            default:
                WD_ERR("not received PROT_RESP_OK!!!\r\n");
                return DRV_ERR;
        }
    }

    return DRV_OK;
}


//验证用获取图像
int32 fp_get_fprint_img(FP_DEVICE_PARAM_STRUCT *this)
{
    RECV_DATA_STRUCT recv_param;

    D_DBG("send PROT_CMD_GETIMAGE command.\n");//未采集到指纹时该指令会循环发送，故不写入log信息
    if(NULL == this)
    {
        WD_ERR("the param is ERROR!\n");
        return DRV_ERR;
    }
    //fp_recv_param_init(&recv_param, 64, 100, 10, 10);
    fp_recv_param_init(&recv_param, 64, 100, 10, 20);//循环时间由10ms改为20ms, add by hcq, 20230608 08:15

    if(DRV_OK == fp_send_cmd(this, PROT_CMD_GETIMAGE, NULL, 0, recv_param))
    {
        switch(fp_resp_type_get(&(this->prot_packet_usb)))
        {
            case PROT_RESP_OK:
                WD_LOG("received PROT_RESP_OK.\r\n");
                fp_upload_fprint_img(this);
                break;
            default:
                WD_ERR("not received PROT_RESP_OK!!!\r\n");
                return DRV_ERR;
        }
    }

    return DRV_OK;
}



//读系统参数
int32 fp_read_sys_param(FP_DEVICE_PARAM_STRUCT *this)
{
    RECV_DATA_STRUCT recv_param;

    WD_DBG("send PROT_CMD_READSYSPARA command.\n");
    if(NULL == this)
    {
        WD_ERR("the param is ERROR!\n");
        return DRV_ERR;
    }

    fp_recv_param_init(&recv_param, 64, 20, 3, 20);//循环时间由10ms改为20ms, add by hcq, 20230608 08:15

    if(DRV_OK == fp_send_cmd(this, PROT_CMD_READSYSPARA, NULL, 0, recv_param))
    {
        switch(fp_resp_type_get(&(this->prot_packet_usb)))
        {
            case PROT_RESP_OK:
                D_DBG("received PROT_RESP_OK.\r\n");
                break;
            default:
                WD_ERR("not received PROT_RESP_OK!!!\r\n");
                return DRV_ERR;
        }
    }

    return DRV_OK;
}


//设置芯片地址
int32 fp_set_chip_addr(FP_DEVICE_PARAM_STRUCT *this, uint32 chip_addr)
{
    RECV_DATA_STRUCT recv_param;
    uint8 buf[10] = {0};
    int index = 0;

    WD_DBG("send PROT_CMD_SETCHIPADDR command.\n");
    if(NULL == this)
    {
        WD_ERR("the param is ERROR!\n");
        return DRV_ERR;
    }

    //fp_recv_param_init(&recv_param, 64, 10, 3, 10);
    fp_recv_param_init(&recv_param, 64, 20, 3, 20);//循环时间由10ms改为20ms, add by hcq, 20230608 08:15

    buf[index++] = (chip_addr >> 24) & 0xff;
    buf[index++] = (chip_addr >> 16) & 0xff;
    buf[index++] = (chip_addr >> 8) & 0xff;
    buf[index++] = chip_addr & 0xff;

    if(DRV_OK == fp_send_cmd(this, PROT_CMD_SETCHIPADDR, buf, index, recv_param))
    {
        switch(fp_resp_type_get(&(this->prot_packet_usb)))
        {
            case PROT_RESP_OK:
                DBG("%s:%d:%s: received PROT_RESP_OK.\r\n", __FILE__, __LINE__, __func__);
                break;
            default:
                WD_ERR("not received PROT_RESP_OK!!!\r\n");
                return DRV_ERR;
        }
    }

    return DRV_OK;
}

//读Flash信息页
int32 fp_read_flash_info_page(FP_DEVICE_PARAM_STRUCT *this)
{
    RECV_DATA_STRUCT recv_param;

    WD_DBG("send PROT_CMD_READINFOPAGE command.\n");
    if(NULL == this)
    {
        WD_ERR("the param is ERROR!\n");
        return DRV_ERR;
    }

    fp_recv_param_init(&recv_param, 64, 20, 5, 20);//循环时间由10ms改为20ms, add by hcq, 20230608 08:15

    if(DRV_OK == fp_send_cmd(this, PROT_CMD_READINFOPAGE, NULL, 0, recv_param))
    {
        switch(fp_resp_type_get(&(this->prot_packet_usb)))
        {
            case PROT_RESP_OK:
                D_DBG("received PROT_RESP_OK.\n");
                //待增加flash信息读取, by hcq, 20230129
                if(DRV_ERR == fp_read_and_parse_prot(this, FLASH_INFO_PAGE_SIZE + 20))
                {
                    WD_ERR("fp_read_and_parse_prot failed!!!\r\n");
                    return DRV_ERR;
                }
                break;
            default:
                WD_ERR("not received PROT_RESP_OK!!!\r\n");
                return DRV_ERR;
        }
    }

    return DRV_OK;
}


//读索引表
int32 fp_read_index_table(FP_DEVICE_PARAM_STRUCT *this, uint8 index_page)
{
    RECV_DATA_STRUCT recv_param;
    uint8 buf[10] = {0};

    WD_DBG("send PROT_CMD_READINDEXTABLE command.\n");
    if(NULL == this)
    {
        WD_ERR("the param is ERROR!\n");
        return DRV_ERR;
    }

    fp_recv_param_init(&recv_param, 64, 20, 10, 20);//循环时间由10ms改为20ms, add by hcq, 20230608 08:15

    buf[0] = index_page;

    if(DRV_OK != fp_send_cmd(this, PROT_CMD_READINDEXTABLE, buf, 1, recv_param))
    {
        WD_ERR("fp_send_cmd failed!!!\r\n");
        return DRV_ERR;
    }

    switch(fp_resp_type_get(&(this->prot_packet_usb)))
    {
        case PROT_RESP_OK:
            D_DBG("received PROT_RESP_OK.\n");
            break;
        default:
            WD_ERR("not received PROT_RESP_OK!!!\r\n");
            return DRV_ERR;
    }


    return DRV_OK;
}


//获取芯片唯一序列号
int32 fp_get_chip_serial_num(FP_DEVICE_PARAM_STRUCT *this)
{
    RECV_DATA_STRUCT recv_param;

    WD_DBG("send PROT_CMD_GETCHIPSN command.\n");
    if(NULL == this)
    {
        WD_ERR("the param is ERROR!\n");
        return DRV_ERR;
    }

    fp_recv_param_init(&recv_param, 64, 20, 3, 20);//循环时间由10ms改为20ms, add by hcq, 20230608 08:15

    if(DRV_OK == fp_send_cmd(this, PROT_CMD_GETCHIPSN, NULL, 0, recv_param))
    {
        switch(fp_resp_type_get(&(this->prot_packet_usb)))
        {
            case PROT_RESP_OK:
                D_DBG("received PROT_RESP_OK.\n");
                {
                    WD_DBG("chip_serial_num: ");
                    for(int i = 0; i < this->chip_serial_num_len; i++)
                    {
                        W_DBG("%02x ", this->chip_serial_num[i]);
                    }
                    W_DBG("\n");
                }
                break;
            default:
                WD_ERR("not received PROT_RESP_OK!!!\r\n");
                return DRV_ERR;
        }
    }

    return DRV_OK;
}



int32 fp_handshake(FP_DEVICE_PARAM_STRUCT *this)
{
    RECV_DATA_STRUCT recv_param;

    WD_DBG("send PROT_CMD_HANDSHAKE command.\n");
    if(NULL == this)
    {
        WD_ERR("the param is ERROR!\n");
        return DRV_ERR;
    }

    //fp_recv_param_init(&recv_param, 230, 10, 3, 10);//此处长度未遵循协议，待确认, by hcq, 20230129
    fp_recv_param_init(&recv_param, 230, 20, 3, 20);//循环时间由10ms改为20ms, add by hcq, 20230608 08:15

    this->handshake_state = 0;

    if(DRV_OK == fp_send_cmd(this, PROT_CMD_HANDSHAKE, NULL, 0, recv_param))
    {
        switch(fp_resp_type_get(&(this->prot_packet_usb)))
        {
            case PROT_RESP_OK:
                D_DBG("received PROT_RESP_OK.\n");
                D_DBG("handshake_state = %d.\n", this->handshake_state);
                break;
            default:
                WD_ERR("not received PROT_RESP_OK!!!\r\n");
                return DRV_ERR;
        }
    }

    return DRV_OK;
}

uint16 fp_get_empty_enroll_id(FP_DEVICE_PARAM_STRUCT *this)
{
    uint16 enroll_id = 0xffff;

    for(int page_num = 0; page_num < INDEX_PAGE_NUM; page_num++)
    {
        if(DRV_OK == fp_read_index_table(this, page_num))
        {
            for(int i = 0; i < 32; i++)
            {
                for(int j = 0; j < 8; j++)
                {
                    if((CURRENT_ENROLL_ID_MIN <= (i*8 + j)) \
                        && (CURRENT_ENROLL_ID_MAX >= (i*8 + j)) \
                        && (0x00 == ((this->index_table_info[page_num][i]>>j) & 0x01)))
                    {
                        enroll_id = i*8 + j;
                        return enroll_id;
                    }
                }
            }
        }
    }

    return enroll_id;
}

int32 fp_auto_enroll_param_init(FP_AUTOENROLL_PARAM_STRUCT *auto_enroll_param,
                                       uint16                      enroll_id,
                                       uint8                       auto_enroll_times)
{
    auto_enroll_param->enroll_id = enroll_id;
    auto_enroll_param->auto_enroll_times = auto_enroll_times;
    auto_enroll_param->validity_check_result = 0xff;
    auto_enroll_param->current_enroll_time = 0;
    auto_enroll_param->current_enroll_flag = 0;
    memset(auto_enroll_param->capture_result, 0xff, AUTOENROLL_TIMES_MAX);
    memset(auto_enroll_param->create_feature_result, 0xff, AUTOENROLL_TIMES_MAX);
    memset(auto_enroll_param->enroll_result, 0xff, AUTOENROLL_TIMES_MAX);
    auto_enroll_param->merge_template_result = 0xff;
    auto_enroll_param->enroll_conflict_result = 0xff;
    auto_enroll_param->store_template_result = 0xff;
    auto_enroll_param->enroll_finish_flag = 0;
    return DRV_OK;
}

uint8 fp_get_current_enroll_time(FP_DEVICE_PARAM_STRUCT *this)
{
    if(NULL == this)
    {
        WD_ERR("the param is ERROR!\n");
        return 0;
    }

    return this->auto_enroll_param.current_enroll_time;
}

uint8 fp_get_enroll_finish_flag(FP_DEVICE_PARAM_STRUCT *this)
{
    if(NULL == this)
    {
        WD_ERR("the param is ERROR!\n");
        return 0;
    }

    return this->auto_enroll_param.enroll_finish_flag;
}

uint8 fp_get_store_template_result(FP_DEVICE_PARAM_STRUCT *this)
{
    if(NULL == this)
    {
        WD_ERR("the param is ERROR!\n");
        return 0;
    }

    return this->auto_enroll_param.store_template_result;
}


uint8 fp_get_enroll_create_feature_result(FP_DEVICE_PARAM_STRUCT *this, uint8 enroll_time)
{
    if(NULL == this)
    {
        WD_ERR("the param is ERROR!\n");
        return 0xff;
    }

    if(enroll_time > AUTOENROLL_TIMES_MAX)
    {
        WD_ERR("enroll_time = %d, error!!!\r\n", enroll_time);
        return 0xff;
    }

    return this->auto_enroll_param.create_feature_result[enroll_time];
}

uint8 fp_get_enroll_result(FP_DEVICE_PARAM_STRUCT *this, uint8 enroll_time)
{
    if(NULL == this)
    {
        WD_ERR("the param is ERROR!\n");
        return 0xff;
    }

    if(enroll_time > AUTOENROLL_TIMES_MAX)
    {
        WD_ERR("enroll_time = %d, error!!!\r\n", enroll_time);
        return 0xff;
    }

    return this->auto_enroll_param.enroll_result[enroll_time];
}

//自动注册模板开始，发送自动注册模板并获取合法检测应答
int32 fp_auto_enroll_start(FP_DEVICE_PARAM_STRUCT *this, uint16 enroll_id, uint8 enroll_times, uint16 param)
{
    RECV_DATA_STRUCT recv_param;
    uint8 buf[10] = {0};
    int index = 0;

    WD_DBG("send PROT_CMD_AUTOENROLL command.\n");
    if(NULL == this)
    {
        WD_ERR("the param is ERROR!\n");
        return DRV_ERR;
    }

    fp_recv_param_init(&recv_param, 64, 20, 3, 20);//循环时间由10ms改为20ms, add by hcq, 20230608 08:15

    fp_auto_enroll_param_init(&(this->auto_enroll_param), enroll_id, enroll_times);

    buf[index++] = (enroll_id >> 8) & 0xff;
    buf[index++] = enroll_id & 0xff;
    buf[index++] = enroll_times;
    buf[index++] = (param >> 8) & 0xff;
    buf[index++] = param & 0xff;

    if(DRV_OK != fp_send_cmd(this, PROT_CMD_AUTOENROLL, buf, index, recv_param))
    {
        WD_ERR("fp_send_cmd failed!!!\n");
        return DRV_ERR;
    }


    switch(this->auto_enroll_param.validity_check_result)
    {
        case PROT_RESP_OK:
            D_DBG("received PROT_RESP_OK.\n");
            break;
        case PROT_RESP_ADDR_OUT_RANGE:
        case PROT_RESP_FPRINTLIB_FULL:
            fp_set_ctrlFlag(this, FP_CONTROL_FLAG_ENROLLID_OUT_RANGE);//录入ID超出范围或存储已满
            WD_ERR("enroll id out of range!!!\n");
            return DRV_ERR;
        default:
            D_DBG("validity_check_result = 0x%02x.\r\n", this->auto_enroll_param.validity_check_result);
            WD_ERR("not received PROT_RESP_OK!!!\n");
            return DRV_ERR;
    }

    return DRV_OK;
}

//获取ms单位的时间增量
int32 fp_get_increment_of_time_ms(struct timeval *tv_old)
{
    struct timeval tv_new;
    long int tv_sec = 0;
    long int tv_usec = 0;
    gettimeofday(&tv_new, NULL);

    if(tv_new.tv_usec < tv_old->tv_usec)
    {
        tv_usec = 1000*1000 + tv_new.tv_usec - tv_old->tv_usec;
        tv_sec = tv_new.tv_sec - 1 - tv_old->tv_sec;
    }
    else
    {
        tv_usec = tv_new.tv_usec - tv_old->tv_usec;
        tv_sec = tv_new.tv_sec - tv_old->tv_sec;
    }

    return (tv_sec*1000*1000 + tv_usec)/1000;
}

//自动注册模板
int32 fp_auto_enroll(FP_DEVICE_PARAM_STRUCT *this, int32 timeout_ms)
{
    WD_DBG("start.\n");
    if(NULL == this)
    {
        WD_ERR("the param is ERROR!\n");
        return DRV_ERR;
    }

    struct timeval tv_current_time;
    gettimeofday(&tv_current_time, NULL);
    while(1)
    {
        fp_read_and_parse_prot(this, 128);  //此处读取字节数应为128，会返回多条应答，若未读取完会出错

        if(0 != this->auto_enroll_param.enroll_finish_flag)
        {
            WD_DBG("received enroll_finish_flag.\n");
            break;
        }

        //设备不存在出错
        if(0 >= fp_get_device_num(this))
        {
            fp_set_ctrlFlag(this, FP_CONTROL_FLAG_DEV_NOT_EXIST);
            return DRV_ERR;
        }

        if(FP_CONTROL_FLAG_STOPPED == fp_get_ctrlFlag(this))
        {
            return DRV_ERR;
        }

        if(timeout_ms < fp_get_increment_of_time_ms(&tv_current_time))
        {
            WD_DBG("enroll timeout!!!\n");
            fp_set_ctrlFlag(this, FP_CONTROL_FLAG_TIMEOUT);
            return DRV_ERR;
        }

        if(0 != this->auto_enroll_param.current_enroll_flag)
        {
            this->auto_enroll_param.current_enroll_flag = 0;
            break;
        }

        usleep(30 * 1000);
    }

    return DRV_OK;
}

int32 fp_auto_identify_param_init(FP_AUTOIDENTIFY_PARAM_STRUCT *identify_param,
                                          uint8 security_level, uint16 identify_id, uint16 param)
{
    identify_param->security_level = security_level;
    identify_param->identify_id = identify_id;
    identify_param->param = param;
    identify_param->validity_check_result = 0xff;
    identify_param->capture_result = 0xff;
    identify_param->search_result = 0xff;
    identify_param->search_num = 0;
    //identify_param->search_id = 0xffff;
    memset((char *)identify_param->search_id, 0xff, sizeof(identify_param->search_num));
    identify_param->score = 0;
    identify_param->identify_finish_flag = 0;
    return DRV_OK;
}

uint8 fp_get_identify_validity_check_result(FP_DEVICE_PARAM_STRUCT *this)
{
    return this->auto_identify_param.validity_check_result;
}

//自动验证指纹
int32 fp_auto_identify(FP_DEVICE_PARAM_STRUCT *this,
                           uint8                   security_level,
                           uint16                  identify_id,
                           uint16                  param,
                           uint16                 *identify_result_id,
                           int32                   timeout_ms)
{
    RECV_DATA_STRUCT recv_param;
    uint8 buf[10] = {0};
    int index = 0;
    struct timeval tv_current_time;

    WD_DBG("send PROT_CMD_AUTOIDENTIFY command.\n");
    if(NULL == this)
    {
        WD_ERR("the param is ERROR!\n");
        return DRV_ERR;
    }

    fp_recv_param_init(&recv_param, 64, 20, 3, 20);//循环时间由10ms改为20ms

    fp_auto_identify_param_init(&(this->auto_identify_param), security_level, identify_id, param);

    buf[index++] = security_level;
    buf[index++] = (identify_id >> 8) & 0xff;
    buf[index++] = identify_id & 0xff;
    buf[index++] = (param >> 8) & 0xff;
    buf[index++] = param & 0xff;

    if(DRV_OK == fp_send_cmd(this, PROT_CMD_AUTOIDENTIFY, buf, index, recv_param))
    {
        switch(this->auto_identify_param.validity_check_result)
        {
            case PROT_RESP_OK:
                WD_DBG("received PROT_RESP_OK.\n");
                gettimeofday(&tv_current_time, NULL);
                while(1)
                {
                    //设备不存在出错
                    if(0 >= fp_get_device_num(this))
                    {
                        fp_set_ctrlFlag(this, FP_CONTROL_FLAG_DEV_NOT_EXIST);
                        return DRV_ERR;
                    }

                    if((0 != timeout_ms) && (timeout_ms < fp_get_increment_of_time_ms(&tv_current_time)))
                    {
                        WD_DBG("identify timeout.\n");
                        fp_set_ctrlFlag(this, FP_CONTROL_FLAG_TIMEOUT);
                        return DRV_ERR;
                    }

                    fp_read_and_parse_prot(this, 64);

                    if((0 != this->auto_identify_param.identify_finish_flag) \
                        || (PROT_RESP_OK != this->auto_identify_param.validity_check_result))
                    {
                        break;
                    }

                    if(FP_CONTROL_FLAG_STOPPED == fp_get_ctrlFlag(this))
                    {
                        fp_onekey_restart_identify(this, get_onekey_powerup_search_id(this), 20);
                        return DRV_ERR;
                    }

                    usleep(20 * 1000);
                }
                break;
            default:
                WD_ERR("not received PROT_RESP_OK!!!\r\n");
                return DRV_ERR;
        }
    }

    if(PROT_RESP_OK != this->auto_identify_param.validity_check_result)
    {
        WD_ERR("validity_check_result = 0x%02x !!!\r\n", \
            this->auto_identify_param.validity_check_result);
        return DRV_ERR;
    }

    WD_DBG("search_result = 0x%02x, search_num = %d, search_id[0] = 0x%04x !!!\r\n", \
            this->auto_identify_param.search_result, this->auto_identify_param.search_num, \
            this->auto_identify_param.search_id[0]);

    if(0 != this->auto_identify_param.search_result)
    {
        WD_ERR("not search id %d !!!\n", identify_id);
        return DRV_OK;
    }

    for(int n = 0; n < this->auto_identify_param.search_num; n++)
    {
        identify_result_id[n] = this->auto_identify_param.search_id[n];
    }

    return DRV_OK;
}

//一键开机自动验证指纹
int32 fp_onekey_powerup_identify(FP_DEVICE_PARAM_STRUCT *this,
                                        uint8                   security_level,
                                        uint16                  identify_id,
                                        uint16                  param,
                                        uint16                 *identify_result_id,
                                        int32                   wait_ms)
{
    RECV_DATA_STRUCT recv_param;
    uint8 buf[10] = {0};
    int index = 0;

    WD_DBG("send PROT_CMD_AUTOIDENTIFY command.\n");
    if(NULL == this)
    {
        WD_ERR("the param is ERROR!\n");
        return DRV_ERR;
    }

    fp_recv_param_init(&recv_param, 64, 20, 3, 20);//循环时间由10ms改为20ms

    fp_auto_identify_param_init(&(this->auto_identify_param), security_level, identify_id, param);

    buf[index++] = security_level;
    buf[index++] = (identify_id >> 8) & 0xff;
    buf[index++] = identify_id & 0xff;
    buf[index++] = (param >> 8) & 0xff;
    buf[index++] = param & 0xff;

    if(DRV_OK == fp_send_cmd(this, PROT_CMD_AUTOIDENTIFY, buf, index, recv_param))
    {
        switch(this->auto_identify_param.validity_check_result)
        {
            case PROT_RESP_OK:
                WD_DBG("received PROT_RESP_OK.\n");
                //gettimeofday(&tv_current_time, NULL);
                for(int count = 0; count < 5; count++)
                {
                    //设备不存在出错
                    if(0 >= fp_get_device_num(this))
                    {
                        //fp_set_ctrlFlag(FP_CONTROL_FLAG_DEV_NOT_EXIST);
                        return DRV_ERR;
                    }

                    fp_read_and_parse_prot(this, 64);

                    if((0 != this->auto_identify_param.identify_finish_flag) \
                        || (PROT_RESP_OK != this->auto_identify_param.validity_check_result))
                    {
                        break;
                    }

                    usleep(wait_ms * 1000);
                }
                break;
            default:
                WD_ERR("not received PROT_RESP_OK!!!\r\n");
                return DRV_ERR;
        }
    }

    if(PROT_RESP_OK != this->auto_identify_param.validity_check_result)
    {
        WD_ERR("validity_check_result = 0x%02x !!!\r\n", \
            this->auto_identify_param.validity_check_result);
        return DRV_ERR;
    }

    WD_DBG("search_result = 0x%02x, search_id[0] = %d.\n", \
            this->auto_identify_param.search_result, this->auto_identify_param.search_id[0]);

    if(0 != this->auto_identify_param.identify_finish_flag)
    {
        set_onekey_powerup_flag(this, 1);
        set_onekey_restart_flag(this, 0);
        gettimeofday(&(this->onekey_powerup.tv_current_time), NULL);//若读取到1键开机结果，15秒后未解锁则清空一键开机状态
    }

    if(0 != this->auto_identify_param.search_result)
    {
        WD_ERR("not search id %d !!!\r\n", \
            identify_id);
        this->onekey_powerup.search_num = 0;
        return DRV_OK;
    }

    this->onekey_powerup.search_num = this->auto_identify_param.search_num;
    for(int n = 0; n < this->auto_identify_param.search_num; n++)
    {
        identify_result_id[n] = this->auto_identify_param.search_id[n];
    }

    return DRV_OK;
}

//uos系统休眠后，按指纹唤醒，调用verify后，在返回结果前会发一次取消，然后重新调用verify，导致一键开机失效
//因此增加保护，记录本次verify结果至一键开机参数中
int32 fp_onekey_restart_identify(FP_DEVICE_PARAM_STRUCT *this, uint16 *identify_result_id, int32 wait_ms)
{
    RECV_DATA_STRUCT recv_param;
    uint8 buf[10] = {0};
    int index = 0;

    WD_LOG("start.\r\n");
    if(NULL == this)
    {
        WD_ERR("the param is ERROR!\n");
        return DRV_ERR;
    }

    init_onekey_powerup_search_id(this);

    for(int count = 0; count < 5; count++)
    {
        //设备不存在出错
        if(0 >= fp_get_device_num(this))
        {
            //fp_set_ctrlFlag(FP_CONTROL_FLAG_DEV_NOT_EXIST);
            return DRV_ERR;
        }

        fp_read_and_parse_prot(this, 64);

        if((0 != this->auto_identify_param.identify_finish_flag) \
            || (PROT_RESP_OK != this->auto_identify_param.validity_check_result))
        {
            break;
        }

        usleep(wait_ms * 1000);
    }

    if(PROT_RESP_OK != this->auto_identify_param.validity_check_result)
    {
        WD_ERR("validity_check_result = 0x%02x !!!\r\n", \
            this->auto_identify_param.validity_check_result);
        return DRV_ERR;
    }

    WD_DBG("search_result = 0x%02x, search_id[0] = %d.\n", \
            this->auto_identify_param.search_result, this->auto_identify_param.search_id[0]);

    if(0 != this->auto_identify_param.identify_finish_flag)
    {
        set_onekey_powerup_flag(this, 1);
        set_onekey_restart_flag(this, 1);
        gettimeofday(&(this->onekey_powerup.tv_restart_begin), NULL);
        gettimeofday(&(this->onekey_powerup.tv_current_time), NULL);//若读取到1键开机结果，15秒后未解锁则清空一键开机状态
    }

    if(0 != this->auto_identify_param.search_result)
    {
        WD_ERR("not search id !!!\r\n");
        this->onekey_powerup.search_num = 0;
        return DRV_OK;
    }

    this->onekey_powerup.search_num = this->auto_identify_param.search_num;
    for(int n = 0; n < this->auto_identify_param.search_num; n++)
    {
        identify_result_id[n] = this->auto_identify_param.search_id[n];
    }

    return DRV_OK;
}

int32 fp_onekey_restart_identify_2(FP_DEVICE_PARAM_STRUCT *this, uint16 *identify_result_id)
{
    //RECV_DATA_STRUCT recv_param;
    int32 search_num = 0;
    //uint8 buf[10] = {0};
    //int index = 0;
    WD_LOG("start.\r\n");
    if(NULL == this)
    {
        WD_ERR("the param is ERROR!\n");
        return DRV_ERR;
    }

    init_onekey_powerup_search_id(this);

    set_onekey_powerup_flag(this, 1);
    set_onekey_restart_flag(this, 1);
    gettimeofday(&(this->onekey_powerup.tv_restart_begin), NULL);//读取休眠开机时一键开机时间
    gettimeofday(&(this->onekey_powerup.tv_current_time), NULL);//若读取到1键开机结果，15秒后未解锁则清空一键开机状态


    WD_DBG("search_num = %d.\r\n", search_num);
    for(int n = 0; n < ENROLL_NUM_MAX; n++)
    {
        if(0xffff == identify_result_id[n])
        {
            break;
        }
        this->onekey_powerup.search_id[n] = identify_result_id[n];
        search_num++;
    }

    this->onekey_powerup.search_num = search_num;

    return DRV_OK;
}




int32 fp_delete_template(FP_DEVICE_PARAM_STRUCT *this, uint16 enroll_id, uint16 num)
{
    RECV_DATA_STRUCT recv_param;
    uint8 buf[10] = {0};
    int index = 0;

    WD_DBG("send PROT_CMD_DELCHAR command.\n");
    WD_DBG("enroll_id = %d, num = %d.\n", enroll_id, num);
    if(NULL == this)
    {
        WD_ERR("the param is ERROR!\n");
        return DRV_ERR;
    }

    fp_recv_param_init(&recv_param, 64, 20, 5, 20);//循环时间由10ms改为20ms, add by hcq, 20230608 08:15

    this->delete_template_result = 0xff;

    buf[index++] = (enroll_id >> 8) & 0xff;
    buf[index++] = enroll_id & 0xff;
    buf[index++] = (num >> 8) & 0xff;
    buf[index++] = num & 0xff;

    if(DRV_OK != fp_send_cmd(this, PROT_CMD_DELCHAR, buf, index, recv_param))
    {
        WD_ERR("fp_send_cmd failed!!!\r\n");
        return DRV_ERR;
    }

    switch(this->delete_template_result)
    {
        case PROT_RESP_OK:
            D_DBG("received PROT_RESP_OK.\r\n");
            break;
        default:
            WD_ERR("delete_template_result = 0x%02x, error!!!\r\n", \
                this->delete_template_result);
            return DRV_ERR;
    }

    return DRV_OK;
}

int32 fp_empty_template(FP_DEVICE_PARAM_STRUCT *this)
{
    RECV_DATA_STRUCT recv_param;

    WD_DBG("send PROT_CMD_EMPTY command.\n");

    fp_recv_param_init(&recv_param, 64, 20, 5, 20);//循环时间由10ms改为20ms, add by hcq, 20230608 08:15
    if(NULL == this)
    {
        WD_ERR("the param is ERROR!\n");
        return DRV_ERR;
    }

    this->empty_template_result = 0xff;

    if(DRV_OK == fp_send_cmd(this, PROT_CMD_EMPTY, NULL, 0, recv_param))
    {
        switch(this->empty_template_result)
        {
            case PROT_RESP_OK:
                DBG("%s:%d:%s: received PROT_RESP_OK.\r\n", __FILE__, __LINE__, __func__);
                break;
            default:
                WD_ERR("empty_template_result = 0x%02x, error!!!\r\n", \
                    this->empty_template_result);
                return DRV_ERR;
        }
    }

    return DRV_OK;
}

//删除数据库中不存在的模板id
//输入index_list为数据库中存在的列表
int32 fp_delete_invalid_template(FP_DEVICE_PARAM_STRUCT *this, uint8 *index_list)
{
    if(NULL == this)
    {
        WD_ERR("the param is ERROR!\n");
        return DRV_ERR;
    }

    if(NULL == index_list)
    {
        WD_ERR("index_list = NULL, error!!!\r\n");
        return DRV_ERR;
    }

    for(int line = 0; line < INDEX_PAGE_NUM; line++)
    {
        if(DRV_OK != fp_read_index_table(this, line))
        {
            continue;
        }

        for(int i = 0; i < 32; i++)
        {
            uint8 fp_value = this->index_table_info[line][i];//模组当前字节值
            uint8 db_value = index_list[line*32 + i];//数据库当前字节值
            if(0 == fp_value)
            {
                continue;
            }

            for(int j = 0; j < 8; j++)
            {
                if((CURRENT_ENROLL_ID_MIN <= (256*line + 8*i + j)) && (CURRENT_ENROLL_ID_MAX >= (256*line + 8*i + j)) \
                    && (fp_value & (0x01<<j)) && (!(db_value & (0x01<<j))))
                {
                    WD_DBG("index = %d is invalid!!!\n", 256*line + 8*i + j);
                    fp_delete_template(this, 256*line + 8*i + j, 1);
                }
            }
        }
    }

    return DRV_OK;
}

int32 fp_set_ctrlFlag(FP_DEVICE_PARAM_STRUCT *this, int32 ctrlFlag)
{
    if(NULL == this)
    {
        WD_ERR("the param is ERROR!\n");
        return DRV_ERR;
    }

    this->ctrlFlag = ctrlFlag;

    return DRV_OK;
}

int32 fp_get_ctrlFlag(FP_DEVICE_PARAM_STRUCT *this)
{
    if(NULL == this)
    {
        WD_ERR("the param is ERROR!\n");
        return DRV_ERR;
    }

    return this->ctrlFlag;
}

//清空模组无效报文
int32 fp_read_invalid_pkg(FP_DEVICE_PARAM_STRUCT *this, int count)
{
    MSG_STRUCT msg;
    int32 read_len = 64;
    USB_DEV_STRUCT *usb_dev = NULL;

    WD_DBG("start.\n");
    if(NULL == this)
    {
        WD_ERR("the param is ERROR!\n");
        return DRV_ERR;
    }

    usb_dev = &(this->usb_dev);
    memset((int8 *)&msg, 0, sizeof(MSG_STRUCT));

    for(int i = 0; i < count; i++)
    {
        if(DRV_OK != usb_read_data(usb_dev, (uint8 *)&msg, read_len, &read_len))
        {
            //ERR("%s:%d:%s: usb_read_data failed!!!\r\n", __FILE__, __LINE__, __func__);
            return DRV_ERR;
        }
    }

    return 0;
}

int32 fp_cancel(FP_DEVICE_PARAM_STRUCT *this)
{
    RECV_DATA_STRUCT recv_param;

    WD_DBG("send PROT_CMD_CANCEL command.\n");
    if(NULL == this)
    {
        WD_ERR("the param is ERROR!\n");
        return DRV_ERR;
    }

    fp_recv_param_init(&recv_param, 64, 20, 5, 20);//循环时间由10ms改为20ms, add by hcq, 20230608 08:15

    this->cancel_result = 0xff;

    if(DRV_OK == fp_send_cmd(this, PROT_CMD_CANCEL, NULL, 0, recv_param))
    {
        switch(this->cancel_result)
        {
            case PROT_RESP_OK:
                D_DBG("received PROT_RESP_OK.\r\n");
                break;
            default:
                WD_ERR("cancel_result = 0x%02x, error!!!\r\n", \
                    this->cancel_result);
                fp_read_invalid_pkg(this, 3);//规避取消报文错位，add by hcq, 20230314
                return DRV_ERR;
        }
    }

    fp_read_invalid_pkg(this, 3);//规避取消报文错位，add by hcq, 20230314
    return DRV_OK;
}


int32 fp_sleep(FP_DEVICE_PARAM_STRUCT *this)
{
    RECV_DATA_STRUCT recv_param;

    WD_DBG("send PROT_CMD_SLEEP command.\n");
    if(NULL == this)
    {
        WD_ERR("the param is ERROR!\n");
        return DRV_ERR;
    }

    this->sleep_result = 0xff;

    fp_recv_param_init(&recv_param, 64, 20, 3, 20);//循环时间由10ms改为20ms, add by hcq, 20230608 08:15

    if(DRV_OK == fp_send_cmd(this, PROT_CMD_SLEEP, NULL, 0, recv_param))
    {
        switch(this->sleep_result)
        {
            case PROT_RESP_OK:
                D_DBG("received PROT_RESP_OK.\r\n");
                break;
            default:
                WD_ERR("sleep_result = 0x%02x, error!!!\r\n", \
                    this->sleep_result);
                return DRV_ERR;
        }
    }

    return DRV_OK;
}

//读有效模板个数
int32 fp_get_valid_template_num(FP_DEVICE_PARAM_STRUCT *this)
{
    RECV_DATA_STRUCT recv_param;

    WD_DBG("send PROT_CMD_VALIDTEMPLATENUM command.\r\n");
    if(NULL == this)
    {
        WD_ERR("the param is ERROR!\n");
        return DRV_ERR;
    }

    this->valid_template_num = 0xffff;

    fp_recv_param_init(&recv_param, 64, 20, 3, 20);//循环时间由10ms改为20ms, add by hcq, 20230608 08:15

    if(DRV_OK == fp_send_cmd(this, PROT_CMD_VALIDTEMPLATENUM, NULL, 0, recv_param))
    {
        switch(fp_resp_type_get(&(this->prot_packet_usb)))
        {
            case PROT_RESP_OK:
                WD_DBG("received PROT_RESP_OK.\r\n");
                WD_DBG("valid_template_num = %d.\r\n", this->valid_template_num);
                break;
            default:
                WD_ERR("not received PROT_RESP_OK!!!\r\n");
                return DRV_ERR;
        }

    }

    return DRV_OK;
}


int fp_set_mode(FP_DEVICE_PARAM_STRUCT *this, char *mode, int len)
{
    RECV_DATA_STRUCT recv_param;
    uint8 buf[100] = {0};
    int index = 0;

    WD_DBG("send PROT_CMD_SET_MODE command.\n");
    if(NULL == this)
    {
        WD_ERR("the param is ERROR!\n");
        return DRV_ERR;
    }

    fp_recv_param_init(&recv_param, 64, 20, 10, 20);//循环时间由10ms改为20ms, add by hcq, 20230608 08:15

    buf[index++] = PROT_SUBCMD_SET_MODE;
    memcpy(&(buf[index]), mode, len);
    index += len;

    if(DRV_OK != fp_send_cmd(this, PROT_CMD_TEST_TYPE, buf, index, recv_param))
    {
        WD_ERR("fp_send_cmd failed!!!\n");
        return DRV_ERR;
    }

    switch(fp_resp_type_get(&(this->prot_packet_usb)))
    {
        case PROT_RESP_OK:
            D_DBG("received PROT_RESP_OK.\n");
            break;
        default:
            WD_ERR("not received PROT_RESP_OK!!!\r\n");
            return DRV_ERR;
    }

    return DRV_OK;
}

#define CMD_PARAM_LEN 8
int fp_reboot(FP_DEVICE_PARAM_STRUCT *this)
{
    RECV_DATA_STRUCT recv_param;
    uint8 cmd_param[CMD_PARAM_LEN] = {0x5A, 0xA5, 0x55, 0xAA, 0x42, 0x44, 0x43, 0x47};
    uint8 buf[100] = {0};
    int index = 0;

    WD_DBG("send PROT_CMD_SET_MODE command.\n");
    if(NULL == this)
    {
        WD_ERR("the param is ERROR!\n");
        return DRV_ERR;
    }

    fp_recv_param_init(&recv_param, 64, 70, 1, 0);//发送后只读取一次应答

    memcpy(&(buf[index]), cmd_param, CMD_PARAM_LEN);
    index += CMD_PARAM_LEN;

    if(DRV_OK != fp_send_cmd(this, PROT_CMD_RTBOOT, buf, index, recv_param))
    {
        WD_ERR("fp_send_cmd failed!!!\n");
        return DRV_ERR;
    }

    switch(fp_resp_type_get(&(this->prot_packet_usb)))
    {
        case PROT_RESP_OK:
            D_DBG("received PROT_RESP_OK.\n");
            break;
        default:
            WD_ERR("not received PROT_RESP_OK!!!\r\n");
            return DRV_ERR;
    }

    return DRV_OK;
}

int fp_set_pc_state(FP_DEVICE_PARAM_STRUCT *this, uint8 pc_state)
{
    RECV_DATA_STRUCT recv_param;
    uint8 buf[100] = {0};
    int index = 0;

    WD_DBG("send PROT_CMD_PS_PC_STATE command.\n");
    if(NULL == this)
    {
        WD_ERR("the param is ERROR!\n");
        return DRV_ERR;
    }

    fp_recv_param_init(&recv_param, 64, 20, 3, 20);//循环时间由10ms改为20ms, add by hcq, 20230608 08:15

    buf[index++] = pc_state;

    if(DRV_OK != fp_send_cmd(this, PROT_CMD_PS_PC_STATE, buf, index, recv_param))
    {
        WD_ERR("fp_send_cmd failed!!!\n");
        return DRV_ERR;
    }

    switch(fp_resp_type_get(&(this->prot_packet_usb)))
    {
        case PROT_RESP_OK:
            D_DBG("received PROT_RESP_OK.\n");
            break;
        default:
            WD_ERR("not received PROT_RESP_OK!!!\n");
            return DRV_ERR;
    }

    return DRV_OK;
}





//获取当前设备数量，0：设备不存在，1：设备存在
int fp_get_device_num(FP_DEVICE_PARAM_STRUCT *this)
{
    if(NULL == this)
    {
        WD_ERR("the param is ERROR!\n");
        return 0;
    }

    if(NULL == usb_get_dev_handle(&(this->usb_dev)))
    {
        return 0;
    }
    else
    {
        return 1;
    }
}


